package com.keyboardr.gamerater;

import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;

import org.json.JSONArray;
import org.json.JSONException;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
import android.widget.ToggleButton;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.keyboardr.gamerater.adapter.MainPagerAdapter;
import com.keyboardr.gamerater.comparator.NameComparator;
import com.keyboardr.gamerater.comparator.RatingComparator;
import com.keyboardr.gamerater.fragment.GamesFragment;
import com.keyboardr.gamerater.fragment.GroupsFragment;
import com.keyboardr.gamerater.fragment.PlayersFragment;
import com.keyboardr.gamerater.fragment.dialog.NewGameDialogFragment;
import com.keyboardr.gamerater.interfaces.GroupContainer;
import com.keyboardr.gamerater.model.Group;
import com.keyboardr.gamerater.model.Player;
import com.keyboardr.gamerater.view.GroupSpinner;

public class RaterActivity extends SherlockFragmentActivity implements
		OnClickListener, GroupContainer {
	private static final NameComparator<Player> NAME_COMPARATOR = new NameComparator<Player>(
			false);
	private static final RatingComparator<Player> RATING_COMPARATOR = new RatingComparator<Player>();
	private static final String STATE_RATING_SORT = "ratingSort";
	private static final String TAG = "RaterActivity";
	private static final int REQUEST_GROUP = 1;
	private ArrayList<Group> mGroups;
	private Group selectedGroup;
	private boolean ratingSort = true;
	private ArrayList<Player> sortedList;
	private boolean deserializationFault;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		if (savedInstanceState != null
				&& savedInstanceState.containsKey(STATE_RATING_SORT)) {
			ratingSort = savedInstanceState.getBoolean(STATE_RATING_SORT);
		}

		final SharedPreferences settings = getPreferences(MODE_PRIVATE);
		ProgressDialog progress = ProgressDialog.show(this, "",
				"Loading.  Please wait...", true);
		deserializationFault = false;
		AsyncTask<Void, Void, ArrayList<Group>> loadFile = new AsyncTask<Void, Void, ArrayList<Group>>() {

			@Override
			protected ArrayList<Group> doInBackground(Void... arg0) {

				JSONArray groups;
				ArrayList<Group> aList = null;
				try {
					groups = new JSONArray(settings.getString("groups", ""));
					Log.d(TAG,
							"loading "
									+ settings.getString("groups",
											"nothing saved"));
					aList = new ArrayList<Group>(groups.length());
					for (int i = 0; i < groups.length(); i++) {
						aList.add(new Group(groups.getJSONObject(i)));
					}
				} catch (JSONException e) {
					deserializationFault = true;
					e.printStackTrace();
				}
				return aList;
			}
		}.execute();

		Button groupSpinner = null;
		ImageButton newPlayerButton = (ImageButton) findViewById(R.id.addPlayerButton);
		if (newPlayerButton != null) {
			newPlayerButton.setOnClickListener(this);
		}

		ToggleButton playerSortButton = (ToggleButton) findViewById(R.id.playerSortButton);
		if (playerSortButton != null) {
			playerSortButton.setOnClickListener(this);
		}

		groupSpinner = (Button) findViewById(R.id.groupSpinner);
		if (groupSpinner != null) {
			groupSpinner.setOnClickListener(this);
		}

		// We have to do this because the fragments getting created by the
		// ViewPager aren't getting detached on orientation change
		ViewPager pager = (ViewPager) findViewById(R.id.pager);
		if (pager == null) {
			FragmentTransaction trans = getSupportFragmentManager()
					.beginTransaction();
			Fragment hiddenPlayerFragment = getSupportFragmentManager()
					.findFragmentByTag("pagerPlayers");
			if (hiddenPlayerFragment != null) {
				trans.detach(hiddenPlayerFragment);
			}
			Fragment hiddenGameFragment = getSupportFragmentManager()
					.findFragmentByTag("pagerGames");
			if (hiddenGameFragment != null) {
				trans.detach(hiddenGameFragment);
			}
			trans.commit();
		}

		TabHost tabHost = (TabHost) findViewById(R.id.tabhost);
		if (tabHost != null) {
			tabHost.setup();

			if (pager != null) {
				MainPagerAdapter pagerAdapter = new MainPagerAdapter(this,
						tabHost, pager);

				pagerAdapter.addTab(
						tabHost.newTabSpec("players").setIndicator(
								getString(R.string.ratings)),
						PlayersFragment.class, null);
				pagerAdapter.addTab(
						tabHost.newTabSpec("games").setIndicator(
								getString(R.string.history)),
						GamesFragment.class, null);

			} else {

				TabSpec spec1 = tabHost.newTabSpec("Tab 1");
				spec1.setContent(R.id.tab1);
				spec1.setIndicator("Ratings");

				TabSpec spec2 = tabHost.newTabSpec("Tab 2");
				spec2.setContent(R.id.tab2);
				spec2.setIndicator("History");

				tabHost.addTab(spec1);
				tabHost.addTab(spec2);
			}
		}

		if (getSupportFragmentManager().findFragmentByTag("groups") == null) {

			groupSpinner = new GroupSpinner(this);
			groupSpinner.setId(R.id.groupSpinner);
			groupSpinner.setOnClickListener(this);
			getSupportActionBar().setCustomView(groupSpinner);
			getSupportActionBar().setDisplayOptions(
					ActionBar.DISPLAY_SHOW_CUSTOM + ActionBar.DISPLAY_SHOW_HOME
							+ ActionBar.DISPLAY_SHOW_TITLE);
		}

		Log.d(TAG, "line 124");
		try {
			mGroups = loadFile.get();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		if (mGroups == null || mGroups.size() == 0 || deserializationFault) {
			mGroups = new ArrayList<Group>();
			mGroups.add(new Group("Default", false));
		}
		progress.dismiss();
		Log.d(TAG, "line 137");
		try {
			selectedGroup = mGroups.get(settings.getInt("selectedGroup", 0));
		} catch (ArrayIndexOutOfBoundsException e) {
			selectedGroup = mGroups.get(0);
		}
		if (groupSpinner != null) {
			groupSpinner.setText(selectedGroup.toString());
		}
		sortedList = new ArrayList<Player>(selectedGroup.getPlayers());
		Collections.sort(sortedList, !ratingSort ? NAME_COMPARATOR
				: RATING_COMPARATOR);
		invalidateOptionsMenu();

	}

	@Override
	public void onResume() {
		super.onResume();

	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putBoolean(STATE_RATING_SORT, ratingSort);
	}

	public void removeGroup(int selection) {
		mGroups.remove(selection);
		if (mGroups.size() == 0) {
			mGroups.add(new Group("Default", true));
		}
		selectGroup(Math.max(0, selection - 1));
	}

	public void addGroup(Group group) {
		mGroups.add(group);
		groupChanged();
	}

	protected void groupChanged() {
		GroupsFragment groups = (GroupsFragment) getSupportFragmentManager()
				.findFragmentByTag("groups");
		if (groups != null) {
			groups.updateGroupSelection();
		} else {
			invalidateOptionsMenu();
		}

		if (findViewById(R.id.groupSpinner) != null) {
			((Button) findViewById(R.id.groupSpinner)).setText(selectedGroup
					.toString());
		}
		itemsChanged();
		SharedPreferences.Editor edit = getPreferences(MODE_PRIVATE).edit();
		edit.putInt("selectedGroup", mGroups.indexOf(selectedGroup));
		edit.commit();
		save();
	}

	public void itemsChanged() {
		sortedList = new ArrayList<Player>(selectedGroup.getPlayers());
		Collections.sort(sortedList, !ratingSort ? NAME_COMPARATOR
				: RATING_COMPARATOR);
		invalidateOptionsMenu();
		PlayersFragment playersFragment = getPlayersFragment();
		if (playersFragment != null && playersFragment.getListAdapter() != null) {
			((BaseAdapter) playersFragment.getListAdapter())
					.notifyDataSetChanged();
		}
		GamesFragment gamesFragment = getGamesFragment();
		if (gamesFragment != null && gamesFragment.getListAdapter() != null) {
			((BaseAdapter) gamesFragment.getListAdapter())
					.notifyDataSetChanged();
		}
	}

	public void save() {
		Log.d(TAG, "Saving");
		Thread saverThread = new Thread(new Runnable() {
			@Override
			public void run() {
				SharedPreferences settings = getPreferences(MODE_PRIVATE);
				SharedPreferences.Editor edit = settings.edit();
				JSONArray jArray = new JSONArray();
				for (Group group : mGroups) {
					jArray.put(group.toJSON());
				}
				edit.putString("groups", jArray.toString());
				edit.commit();
				Log.d(TAG, jArray.toString());
			}
		});
		saverThread.run();
	}

	public Group getSelectedGroup() {
		return selectedGroup;
	}

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.playerSortButton:
			ratingSort = !((ToggleButton) view).isChecked();
			itemsChanged();
			break;
		case R.id.newGameButton:
			Log.d(TAG, "newGameButton pressed");
			newGame();
			break;
		case R.id.addPlayerButton:
			newPlayer();
			break;
		case R.id.groupSpinner:
			Intent request = new Intent();
			request.putExtra(GroupActivity.GROUP_KEY, mGroups);
			request.putExtra(GroupActivity.SELECTION_KEY,
					getSelectedGroupPosition());
			request.setClass(this, GroupActivity.class);
			startActivityForResult(request, REQUEST_GROUP);
			break;
		default:
			throw new AssertionError("Undefined button catch");
		}
	}

	protected void addPlayer(String first, String last, int rating) {
		selectedGroup.addPlayer(new Player(first, last, rating));
		itemsChanged();
		save();
	}

	public void playGame(Player winner, Player loser, boolean draw,
			double handicap) {
		selectedGroup.playAGame(draw, winner, loser, handicap);
		itemsChanged();
		save();
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		switch (requestCode) {
		case REQUEST_GROUP:
			if (resultCode == -1) {
				return;
			}
			Bundle extras = data.getExtras();
			mGroups = (ArrayList<Group>) extras.get(GroupActivity.GROUP_KEY);
			if (resultCode >= 0) {
				selectedGroup = mGroups.get(resultCode);
			}
			groupChanged();
		}
	}

	public ArrayList<Player> getSortedList() {
		return sortedList;
	}

	@Override
	public void selectGroup(int position) {
		selectedGroup = mGroups.get(position);
		groupChanged();
	}

	@Override
	public ArrayList<Group> getGroupList() {
		return mGroups;
	}

	@Override
	public int getSelectedGroupPosition() {
		return mGroups.indexOf(selectedGroup);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		MenuInflater inflater = getSupportMenuInflater();
		inflater.inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		if (menu.findItem(R.id.newGame) != null) {
			if (selectedGroup != null) {
				menu.findItem(R.id.newGame).setVisible(
						selectedGroup.getPlayers().size() >= 2);
			}
			menu.findItem(R.id.ratingSort).setChecked(ratingSort);
			return true;
		}
		return false;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		PlayersFragment playersFragment = getPlayersFragment();
		GamesFragment gamesFragment = getGamesFragment();
		switch (item.getItemId()) {
		case R.id.ratingSort:
			item.setChecked(!item.isChecked());
			ratingSort = item.isChecked();
			playersFragment.clearSelection();
			gamesFragment.setFilter(null);
			itemsChanged();
			return true;
		case R.id.newGame:
			newGame();
			return true;
		case R.id.about:
			Intent intent = new Intent(Intent.ACTION_SEND);
			intent.setType("message/rfc882");
			intent.putExtra(Intent.EXTRA_EMAIL,
					new String[] { getString(R.string.dev_email) });
			intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name)
					+ " app");
			startActivity(intent);
			return true;
		case android.R.id.home:
			playersFragment.clearSelection();
			gamesFragment.setFilter(null);
			return true;
		}
		return false;
	}

	protected PlayersFragment getPlayersFragment() {
		PlayersFragment playersFragment = (PlayersFragment) getSupportFragmentManager()
				.findFragmentByTag("players");
		if (playersFragment == null) {
			playersFragment = (PlayersFragment) getSupportFragmentManager()
					.findFragmentByTag("pagerPlayers");
		}
		return playersFragment;
	}

	protected GamesFragment getGamesFragment() {
		GamesFragment gamesFragment = (GamesFragment) getSupportFragmentManager()
				.findFragmentByTag("games");
		if (gamesFragment == null) {
			gamesFragment = (GamesFragment) getSupportFragmentManager()
					.findFragmentByTag("pagerGames");
		}
		return gamesFragment;
	}

	public void newPlayer() {
		showDialog(R.id.dialog_new_player);
	}

	private Dialog newPlayerDialog() {
		Log.d(TAG, "addPlayerButton pressed");
		final Dialog playerDialog = new Dialog(this);
		playerDialog.setContentView(R.layout.new_player_layout);
		playerDialog.setTitle(R.string.newPlayer);

		final CheckBox ratingCheck = (CheckBox) playerDialog
				.findViewById(R.id.defaultRatingCheck);
		ratingCheck.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View paramView) {
				playerDialog.findViewById(R.id.ratingRow).setVisibility(
						((CheckBox) paramView).isChecked() ? View.GONE
								: View.VISIBLE);
			}
		});

		Button playerOkButton = (Button) playerDialog
				.findViewById(R.id.playerOK);
		playerOkButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String first = ((EditText) playerDialog
						.findViewById(R.id.firstNameInput)).getText()
						.toString();
				String last = ((EditText) playerDialog
						.findViewById(R.id.lastNameInput)).getText().toString();
				int rating;
				if (ratingCheck.isChecked()) {
					rating = 1300;
				} else {
					rating = Integer.valueOf(((EditText) playerDialog
							.findViewById(R.id.ratingInput)).getText()
							.toString());
				}
				addPlayer(first, last, rating);
				playerDialog.dismiss();
			}

		});
		Button playerCancelButton = (Button) playerDialog
				.findViewById(R.id.playerCancel);
		playerCancelButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				playerDialog.cancel();
			}
		});
		playerDialog.getWindow().setLayout(LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT);
		return playerDialog;
	}

	private void newGame() {
		new NewGameDialogFragment().show(getSupportFragmentManager(), null);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case R.id.dialog_new_player:
			return newPlayerDialog();
		}
		return null;
	}

}